﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Net;
using System.Xml;

using DotNetNuke.Common;
using DotNetNuke.ComponentModel;
using DotNetNuke.Entities.Host;
using DotNetNuke.Security;
using DotNetNuke.Services.FileSystem;
using DotNetNuke.Instrumentation;
using SharePointFolderProvider.WSLists;
using SharePointFolderProvider.WSDws;
using SharePointFolderProvider.WSCopy;

namespace SharePointFolderProvider
{
    public class SharePointFolderProvider : FolderProvider
    {
        private static readonly string encryptionKey = Host.GUID;
        private static readonly PortalSecurity portalSecurity = new PortalSecurity();
        private const string LISTS = @"_vti_bin/Lists.asmx";
        private const string DWS = @"_vti_bin/Dws.asmx";
        private const string COPY = @"_vti_bin/Copy.asmx";
        private const string USERNAME = "UserName";
        private const string DOMAIN = "Domain";
        private const string PASSWORD = "Password";
        private const string SHAREPOINTHOSTURL = "SharePointHostUrl";
        private const string DOCUMENTLIBRARY = "DocumentLibrary";
        private const string DOCUMENTLIBRARYVIEWNAME = "DocumentLibraryViewName";

        private Lists _listsService;
        private Dws _dwsService;
        private Copy _copyService;
        // Web Service Lists
        public Lists ListsService 
        {
            get
            {
                if (_listsService == null)
                    _listsService = new Lists();
                return _listsService;
            }
        }
        // Web Service Dws (Document Workspace) 
        public Dws DwsService
        {
            get
            {
                if (_dwsService == null)
                    _dwsService = new Dws();
                return _dwsService;
            }
        }
        // Web Service Copy 
        public Copy CopyService
        {
            get
            {
                if (_copyService == null)
                    _copyService = new Copy();
                return _copyService;
            }
        }

        /// <summary>
        /// Add file to folder 
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="fileName"></param>
        /// <param name="content"></param>
        public override void AddFile(IFolderInfo folder, string fileName, Stream content)
        {
            Requires.NotNull("folder", (object)folder);
            Requires.NotNullOrEmpty("fileName", fileName);
            Requires.NotNull("content", (object)content);
            UpdateFile(folder, fileName, content);
        }

        /// <summary>
        /// Add a new folder 
        /// </summary>
        /// <param name="folderPath"></param>
        /// <param name="folderMapping"></param>
        public override void AddFolder(string folderPath, FolderMappingInfo folderMapping)
        {
            Requires.NotNull("folderPath", (object)folderPath);
            Requires.NotNull("folderMapping", (object)folderMapping);
            // Add a file folder
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            if (folderPath.EndsWith("/"))
                folderPath = folderPath.TrimEnd('/');
            DwsService.Credentials = new NetworkCredential(userName, passWord, domain);
            DwsService.Url = sharepointHostUrl + DWS;
            try
            {
                string strResult = DwsService.CreateFolder(folderPath);
                if (IsDwsErrorResult(strResult))
                {
                    throw new Exception("Add Folder failed");
                }
            }
            catch (Exception ex)
            {
                DnnLog.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// Delete a file
        /// </summary>
        /// <param name="file"></param>
        public override void DeleteFile(IFileInfo file)
        {
            Requires.NotNull("file", (object)file);
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(file.FolderMappingID);
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            ListsService.Credentials = new NetworkCredential(userName, passWord, domain);
            ListsService.Url = sharepointHostUrl + LISTS;
            // Get ViewID and ListID of selected document library
            XmlNode ndListView = ListsService.GetListAndView(documentLibraryName.TrimEnd('/'), "");
            string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;
            string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;
            // Delete selected document
            XmlDocument xmlDoc = new XmlDocument();
            XmlElement elBatch = xmlDoc.CreateElement("Batch");
            // Attention: file path
            elBatch.InnerXml = @"<Method ID='1' Cmd='Delete'>
                                  <Field Name='ID'>1</Field>
                                  <Field Name='FileRef'>" + (sharepointHostUrl + file.RelativePath) + "</Field>" +
                                "</Method>";
            elBatch.SetAttribute("ListVersion", "1");
            elBatch.SetAttribute("ViewName", strViewID);
            try
            {
                XmlNode ndReturn = ListsService.UpdateListItems(strListID, elBatch);
                if (ndReturn.ChildNodes[0].ChildNodes[0].InnerText.Equals("0x00000000"))
                    return;
                else
                    throw new Exception("Delete File failed");
            }
            catch (Exception ex)
            {
                DnnLog.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// Delete a folder
        /// </summary>
        /// <param name="folder"></param>
        public override void DeleteFolder(IFolderInfo folder)
        {
            Requires.NotNull("folder", (object)folder);
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(folder.FolderMappingID);
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            /**
             * Determine whether a document library or a normal folder. If it is a document library, then you do 
             * not have rights to delete it. 
             */ 
            if (folder.FolderPath == documentLibraryViewName)
            {
                return;
            }
            else
            {
                // Delete a folder
                DwsService.Credentials = new NetworkCredential(userName, passWord, domain);
                DwsService.Url = sharepointHostUrl + DWS;
                string folderPath = folder.FolderPath;
                if (folderPath.EndsWith("/"))
                    folderPath = folderPath.TrimEnd('/');
                try
                {
                    string strResult = DwsService.DeleteFolder(folderPath);
                    if (IsDwsErrorResult(strResult))
                    {
                        throw new Exception("Delete Folder failed");
                    }
                }
                catch (Exception ex)
                {
                    DnnLog.Error(ex);
                    throw;
                }
            }
        }

        /// <summary>
        /// Determine whether a file exists under a folder
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public override bool FileExists(IFolderInfo folder, string fileName)
        {
            Requires.NotNull("folder", (object)folder);
            Requires.NotNullOrEmpty("fileName", fileName);
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(folder.FolderMappingID);
            XmlDocument xmlDoc = new XmlDocument();
            XmlNode ndListItems = GetItems(folderMapping, folder.FolderPath, "0");
            if (ndListItems == null)
                return false;
            else
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList files = xmlDoc.GetElementsByTagName("z:row");
                for (int i = 0; i < files.Count; i++)
                {
                    if ((files.Item(i).Attributes["ows_LinkFilename"].Value != null) && (files.Item(i).Attributes["ows_LinkFilename"].Value.Equals(fileName)))
                    {
                        return true;
                    }
                    else
                    {
                        if ((files.Item(i).Attributes["ows_BaseName"].Value + "." + files.Item(i).Attributes["ows_DocIcon"].Value).Equals(fileName))
                            return true;
                    }
                }
                return false;
            }
        }

        /// <summary>
        /// Determine whether a folder exists
        /// </summary>
        /// <param name="folderPath"></param>
        /// <param name="folderMapping"></param>
        /// <returns></returns>
        public override bool FolderExists(string folderPath, FolderMappingInfo folderMapping)
        {
            Requires.NotNull("folderPath", (object)folderPath);
            Requires.NotNull("folderMapping", (object)folderMapping);
            if (folderPath.Length == 0)
                return true;
            else
            {
                // Process folder path
                if (folderPath.EndsWith("/"))
                    folderPath = folderPath.TrimEnd('/');
                XmlDocument xmlDoc = new XmlDocument();
                XmlNode ndListItems = GetItems(folderMapping, "", "1");
                if (ndListItems == null)
                    return false;
                else
                {
                    xmlDoc.LoadXml(ndListItems.OuterXml);
                    XmlNodeList folders = xmlDoc.GetElementsByTagName("z:row");
                    string folderServerUrl = null;
                    foreach (XmlNode folder in folders)
                    {
                        folderServerUrl = folder.Attributes["ows_ServerUrl"].Value;
                        if (folderServerUrl.Contains(folderPath))
                            return true;
                    }
                    return false;
                }            
            }
        }

        /// <summary>
        /// Get attributes of a file
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public override FileAttributes? GetFileAttributes(IFileInfo file)
        {
            return new FileAttributes?();
        }

        /// <summary>
        /// Get size of a file
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public override long GetFileSize(IFileInfo file)
        {
            Requires.NotNull("file", file);
            return file.Size;
        }

        /// <summary>
        /// Get file stream of a file
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public override Stream GetFileStream(IFolderInfo folder, string fileName)
        {
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(folder.FolderMappingID);
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            // Prepare to generate a byte array of a document 
            CopyService.Credentials = new NetworkCredential(userName, passWord, domain);
            CopyService.Url = sharepointHostUrl + COPY;
            // Attention: copySource
            string copySource = sharepointHostUrl + folder.FolderPath + fileName;
            FieldInformation copyFieldInfo = new FieldInformation();
            FieldInformation[] copyFieldInfoArray = { copyFieldInfo };
            byte[] copyByteArray;
            try
            {
                CopyService.GetItem(copySource, out copyFieldInfoArray, out copyByteArray);
                Stream str = new MemoryStream(copyByteArray);
                return str;
            }
            catch (Exception ex)
            {
                DnnLog.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// Get file stream of a file
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public override Stream GetFileStream(IFileInfo file)
        {
            Requires.NotNull("file", (object)file);
            return GetFileStream(ComponentBase<IFolderManager, FolderManager>.Instance.GetFolder(file.FolderId), file.FileName);
        }

        /// <summary>
        /// Get URL of a file
        /// Moment it is not clear to know how and where this function is used, so just return back its relative path. 
        /// Later maybe it needs to be modified.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public override string GetFileUrl(IFileInfo file)
        {
            return file.RelativePath;
        }

        /// <summary>
        /// Get all files under a folder
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public override string[] GetFiles(IFolderInfo folder)
        {
            Requires.NotNull("folder", (object)folder);
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(folder.FolderMappingID);
            XmlDocument xmlDoc = new XmlDocument();
            XmlNode ndListItems = GetItems(folderMapping, folder.FolderPath, "0");
            if (ndListItems == null)
                return null;
            else
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList files = xmlDoc.GetElementsByTagName("z:row");
                List<string> fileNames = new List<string>();
                for (int i = 0; i < files.Count; i++)
                {
                    if (files.Item(i).Attributes["ows_LinkFilename"].Value != null)
                    {
                        fileNames.Add(files.Item(i).Attributes["ows_LinkFilename"].Value);
                    }
                    else
                        fileNames.Add(files.Item(i).Attributes["ows_BaseName"].Value + "." + files.Item(i).Attributes["ows_DocIcon"].Value);
                }
                return fileNames.ToArray();
            }
        }

        /// <summary>
        /// Gets URL of the image to display in FileManager tree
        /// </summary>
        /// <returns></returns>
        public override string GetFolderProviderIconPath()
        {
            return Globals.ResolveUrl("~/Providers/FolderProviders/SharePointFolderProvider/Images/icon_sp.png");
        }

        /// <summary>
        /// At this moment this method not used
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public override DateTime GetLastModificationTime(IFileInfo file)
        {
            return file.LastModificationTime;
        }

        /// <summary>
        /// Get all folders under a specified path
        /// </summary>
        /// <param name="folderPath"></param>
        /// <param name="folderMapping"></param>
        /// <returns></returns>
        public override IEnumerable<string> GetSubFolders(string folderPath, FolderMappingInfo folderMapping)
        {
            Requires.NotNull("folderMapping", (object)folderMapping);
            // Attention: use document library view name here
            string documentLibraryViewName = GetSetting(folderMapping, DOCUMENTLIBRARYVIEWNAME);
            if (!documentLibraryViewName.EndsWith("/"))
                documentLibraryViewName = documentLibraryViewName + "/";
            List<string> subFolders = new List<string>();
            if (folderPath.Length == 0)
            {
                subFolders.Add(documentLibraryViewName);
                return subFolders.ToList<string>();
            }
            else
            {
                XmlDocument xmlDoc = new XmlDocument();
                XmlNode ndListItems = GetItems(folderMapping, folderPath, "1");
                if (ndListItems == null)
                    return null;
                else
                {
                    xmlDoc.LoadXml(ndListItems.OuterXml);
                    XmlNodeList folders = xmlDoc.GetElementsByTagName("z:row");
                    for (int i = 0; i < folders.Count; i++)
                    {
                        string folderName = folders.Item(i).Attributes["ows_LinkFilename"].Value;
                        string folderServerUrl = folders.Item(i).Attributes["ows_ServerUrl"].Value;

                        if (folderName != null && folderServerUrl != null)
                        {
                            if (folderServerUrl.Contains(folderPath + folderName))
                            {
                                subFolders.Add(folderPath + folderName + "/");
                            }
                        }
                    }
                    return subFolders.ToList<string>();
                }
            }
        }

        /// <summary>
        /// At this moment it is not clear when to use this method
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public override bool IsInSync(IFileInfo file)
        {
            return false;
        }

        /// <summary>
        /// Rename a file
        /// </summary>
        /// <param name="file"></param>
        /// <param name="newFileName"></param>
        public override void RenameFile(IFileInfo file, string newFileName)
        {
            Requires.NotNull("file", file);
            Requires.NotNullOrEmpty("newFileName", newFileName);
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(file.FolderMappingID);
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            ListsService.Credentials = new NetworkCredential(userName, passWord, domain);
            ListsService.Url = sharepointHostUrl + LISTS;

            XmlDocument xmlDoc = new XmlDocument();
            XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
            XmlNode ndListItems = null;
            // Attention: value of file.Folder is relative path 
            ndQueryOptions.InnerXml = @"<QueryOptions>
                                          <ViewAttributes Scope='RecursiveAll'/>
                                          <Folder>" +
                                            file.Folder +
                                          "</Folder>" +
                                       "</QueryOptions>";
            ndViewFields.InnerXml = "";
            ndQuery.InnerXml = @"<Where>
                                   <Eq>
                                     <FieldRef Name='FSObjType'/>
                                       <Value Type='Lookup'>0</Value>
                                   </Eq>
                                 </Where>";
            try
            {
                ndListItems = ListsService.GetListItems(documentLibraryName.TrimEnd('/'), null, ndQuery, ndViewFields, null,
                    ndQueryOptions, null);
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList files = xmlDoc.GetElementsByTagName("z:row");
                string fileID = null;
                string fileServerUrl = null;
                string fileExtension = null;
                string fileAbsoluteUrl = null;
                for (int i = 0; i < files.Count; i++)
                {
                    fileServerUrl = files.Item(i).Attributes["ows_ServerUrl"].Value;
                    if (fileServerUrl != null && fileServerUrl.Contains(file.RelativePath))
                    {
                        fileID = files.Item(i).Attributes["ows_ID"].Value;
                        fileExtension = files.Item(i).Attributes["ows_DocIcon"].Value;
                        fileAbsoluteUrl = files.Item(i).Attributes["ows_EncodedAbsUrl"].Value;
                        break;
                    }
                }
                if (fileID != null && fileAbsoluteUrl != null)
                {
                    XmlNode ndListView = ListsService.GetListAndView(documentLibraryName.TrimEnd('/'), "");
                    string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;
                    string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;
                    // Process newFileName
                    string processedNewFileName = null;
                    if (newFileName.EndsWith(fileExtension))
                    {
                        processedNewFileName = newFileName.TrimEnd(fileExtension.ToCharArray());
                        if (processedNewFileName.EndsWith("."))
                            processedNewFileName = processedNewFileName.TrimEnd('.');
                    }
                    XmlElement elBatch = xmlDoc.CreateElement("Batch");
                    elBatch.InnerXml = @"<Method ID='1' Cmd='Update'>
                                           <Field Name='ID'>" +
                                             fileID +
                                           "</Field>" +
                                           "<Field Name='FileRef'>" +
                                             fileAbsoluteUrl +
                                           "</Field>" +
                                           "<Field Name='BaseName'>" +
                                             processedNewFileName +
                                           "</Field>" +
                                        "</Method>";
                    elBatch.SetAttribute("ListVersion", "1");
                    elBatch.SetAttribute("ViewName", strViewID);
                    XmlNode ndReturn = ListsService.UpdateListItems(strListID, elBatch);
                    if (ndReturn.ChildNodes[0].ChildNodes[0].InnerText.Equals("0x00000000"))
                        return;
                    else
                        throw new Exception("Rename File failed");
                }
            }
            catch (Exception ex)
            {
                DnnLog.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// At this moment, it is not clear how to rename folder in File Manager 
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="newFolderName"></param>
        public override void RenameFolder(IFolderInfo folder, string newFolderName)
        {
            Requires.NotNull("folder", folder);
            Requires.NotNullOrEmpty("newFolderName", newFolderName);
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(folder.FolderMappingID);
            XmlDocument xmlDoc = new XmlDocument();
            XmlNode ndListItems = GetItems(folderMapping, "", "1");
            if (ndListItems != null)
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList folders = xmlDoc.GetElementsByTagName("z:row");
                string folderID = null;
                string folderServerUrl = null;
                string folderAbsoluteUrl = null;
                for (int i = 0; i < folders.Count; i++)
                {
                    folderServerUrl = folders.Item(i).Attributes["ows_ServerUrl"].Value;
                    if (folderServerUrl != null && folderServerUrl.Contains(folder.FolderPath.TrimEnd('/')))
                    {
                        folderID = folders.Item(i).Attributes["ows_ID"].Value;
                        folderAbsoluteUrl = folders.Item(i).Attributes["ows_EncodedAbsUrl"].Value;
                        break;
                    }
                }
                // Rename folder
                if (folderID != null && folderAbsoluteUrl != null)
                {
                    // Get document library name
                    string documentLibraryName = GetSetting(folderMapping, DOCUMENTLIBRARY);
                    XmlNode ndListView = ListsService.GetListAndView(documentLibraryName.TrimEnd('/'), "");
                    string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;
                    string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;
                    XmlElement elBatch = xmlDoc.CreateElement("Batch");
                    elBatch.InnerXml = @"<Method ID='1' Cmd='Update'>
                                           <Field Name='ID'>" +
                                             folderID +
                                           "</Field>" +
                                           "<Field Name='FileRef'>" +
                                             folderAbsoluteUrl +
                                           "</Field>" +
                                           "<Field Name='BaseName'>" +
                                             newFolderName +
                                           "</Field>" +
                                        "</Method>";
                    elBatch.SetAttribute("ListVersion", "1");
                    elBatch.SetAttribute("ViewName", strViewID);
                    try
                    {
                        XmlNode ndReturn = ListsService.UpdateListItems(strListID, elBatch);
                        if (ndReturn.ChildNodes[0].ChildNodes[0].InnerText.Equals("0x00000000"))
                            return;
                        else
                            throw new Exception("Rename Folder failed");
                    }
                    catch (Exception ex)
                    {
                        DnnLog.Error(ex);
                        throw;
                    }
                }
            }
        }

        /// <summary>
        /// At this moment we do not support file attributes
        /// so this method is not implemented
        /// </summary>
        /// <param name="file"></param>
        /// <param name="fileAttributes"></param>
        public override void SetFileAttributes(IFileInfo file, FileAttributes fileAttributes)
        {
        }

        /// <summary>
        /// Indicating if the underlying system supports file attributes
        /// </summary>
        /// <returns></returns>
        public override bool SupportsFileAttributes()
        {
            return false;
        }

        /// <summary>
        /// Updates the content of the specified file
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="fileName"></param>
        /// <param name="content"></param>
        public override void UpdateFile(IFolderInfo folder, string fileName, Stream content)
        {
            IFolderMappingController instance = ComponentBase<IFolderMappingController, FolderMappingController>.Instance;
            FolderMappingInfo folderMapping = instance.GetFolderMapping(folder.FolderMappingID);
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            // Prepare to upload a file
            CopyService.Credentials = new NetworkCredential(userName, passWord, domain);
            CopyService.Url = sharepointHostUrl + COPY;
            // Attention: copyDest
            string[] copyDest = { (sharepointHostUrl + folder.FolderPath + fileName) };
            FieldInformation copyFieldInfo = new FieldInformation();
            FieldInformation[] copyFieldInfoArray = { copyFieldInfo };
            byte[] copyByteArray = new Byte[content.Length];
            content.Read(copyByteArray, 0, Convert.ToInt32(content.Length));
            CopyResult copyResult1 = new CopyResult();
            CopyResult copyResult2 = new CopyResult();
            CopyResult[] copyResultArray = { copyResult1, copyResult2 };
            // Upload a file
            try
            {
                uint copyUint = CopyService.CopyIntoItems(" ", copyDest, copyFieldInfoArray, copyByteArray, out copyResultArray);
                if (copyUint == 0)
                {
                    foreach (CopyResult copyResult in copyResultArray)
                    {
                        if (copyResult.ErrorMessage != null)
                        {
                            throw new Exception("Upload File failed");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                DnnLog.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// Updates the content of the specified file
        /// </summary>
        /// <param name="file"></param>
        /// <param name="content"></param>
        public override void UpdateFile(IFileInfo file, Stream content)
        {
            Requires.NotNull("file", (object)file);
            Requires.NotNull("content", (object)content);
            UpdateFile(ComponentBase<IFolderManager, FolderManager>.Instance.GetFolder(file.FolderId), file.FileName, content);
        }

        /// <summary>
        /// Get value of an encrypted specified setting
        /// </summary>
        /// <param name="folderMapping"></param>
        /// <param name="settingName"></param>
        /// <returns></returns>
        private string GetEncryptedSetting(FolderMappingInfo folderMapping, string settingName)
        {
            return portalSecurity.Decrypt(encryptionKey, folderMapping.FolderMappingSettings[settingName].ToString());
        }

        /// <summary>
        /// Get value of a specified setting
        /// </summary>
        /// <param name="folderMapping"></param>
        /// <param name="settingName"></param>
        /// <returns></returns>
        private string GetSetting(FolderMappingInfo folderMapping, string settingName)
        {
            return folderMapping.FolderMappingSettings[settingName].ToString();
        }

        /// <summary>
        /// Process whether Dws web services works well or not
        /// </summary>
        /// <param name="ResultFragment"></param>
        /// <returns></returns>
        private bool IsDwsErrorResult(string ResultFragment)
        {
            StringReader srResult = new StringReader(ResultFragment);
            XmlTextReader xtr = new XmlTextReader(srResult);
            xtr.Read();
            if (xtr.Name.Equals("Error"))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Get necessary information for web services
        /// </summary>
        /// <param name="folderMapping"></param>
        /// <param name="userName"></param>
        /// <param name="domain"></param>
        /// <param name="passWord"></param>
        /// <param name="sharepointHostUrl"></param>
        /// <param name="documentLibraryName"></param>
        private void GetInformation(FolderMappingInfo folderMapping, out string userName, out string domain, out string passWord, out string sharepointHostUrl, out string documentLibraryName, out string documentLibraryViewName)
        {
            userName = GetEncryptedSetting(folderMapping, USERNAME);
            domain = GetEncryptedSetting(folderMapping, DOMAIN);
            passWord = GetEncryptedSetting(folderMapping, PASSWORD);
            sharepointHostUrl = GetEncryptedSetting(folderMapping, SHAREPOINTHOSTURL);
            documentLibraryName = GetSetting(folderMapping, DOCUMENTLIBRARY);
            documentLibraryViewName = GetSetting(folderMapping, DOCUMENTLIBRARYVIEWNAME);
            // Process SharePoint Url, Document Library (View) name
            if (!sharepointHostUrl.EndsWith("/"))
                sharepointHostUrl = sharepointHostUrl + "/";
            if (!documentLibraryName.EndsWith("/"))
                documentLibraryName = documentLibraryName + "/";
            if (!documentLibraryViewName.EndsWith("/"))
                documentLibraryViewName = documentLibraryViewName + "/";
        }

        /// <summary>
        /// Get Folders or Files inside a folder
        /// </summary>
        /// <param name="folderMapping"></param>
        /// <param name="folderPath"></param>
        /// <param name="itemType"> "0" means File, "1" means Folder </param>
        /// <returns></returns>
        private XmlNode GetItems(FolderMappingInfo folderMapping, string folderPath, string itemType)
        {
            XmlNode ndListItems = null;
            XmlDocument xmlDoc = new XmlDocument();
            XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
            string userName, domain, passWord, sharepointHostUrl, documentLibraryName, documentLibraryViewName;
            // Prepare Lists service
            GetInformation(folderMapping, out userName, out domain, out passWord, out sharepointHostUrl, out documentLibraryName, out documentLibraryViewName);
            ListsService.Credentials = new NetworkCredential(userName, passWord, domain);
            ListsService.Url = sharepointHostUrl + LISTS;
            // Attention: folderPath
            ndQueryOptions.InnerXml = @"<QueryOptions>
                                          <ViewAttributes Scope='RecursiveAll'/>
                                          <Folder>" +
                                            folderPath +
                                          "</Folder>" +
                                       "</QueryOptions>";
            ndViewFields.InnerXml = "";
            ndQuery.InnerXml = @"<Where>
                                   <Eq>
                                     <FieldRef Name='FSObjType'/>
                                       <Value Type='Lookup'>" +
                                         itemType +
                                      "</Value>" +
                                    "</Eq>" +
                                "</Where>";
            try
            {
                ndListItems = ListsService.GetListItems(documentLibraryName.TrimEnd('/'), null, ndQuery, ndViewFields, null,
                    ndQueryOptions, null);
                return ndListItems;
            }
            catch (Exception ex)
            {
                DnnLog.Error(ex);
                throw;
            }
        }
    }
}